#include "StyleMgr.h"

#include <QDir>
#include <QFileInfo>
#include <QFileSystemWatcher>
#include <QJsonDocument>
#include <QJsonObject>
#include <QJsonValue>
#include <QSettings>
#include <map>

#include "FileSys.h"
#include "Utility.h"

class ResourceHolder {
 public:
  ResourceHolder() = default;
  void init(StyleMgr::StyleType style);
  void loadColors(StyleMgr::StyleType style);
  void setDftSize();

  QColor color(const QString& crName);
  int size(const QString& sizeName);
  void changeStyle(StyleMgr::StyleType style);

  void loadColorFromFile(const QString& cfgPath);

 private:
  std::map<QString, QColor> m_colors;
  std::map<QString, int> m_sizes;
};

void ResourceHolder::init(StyleMgr::StyleType style) {
  loadColors(style);
  setDftSize();
}

void ResourceHolder::loadColors(StyleMgr::StyleType style) {
  QString cfgFilePath = style == StyleMgr::StyleType::kDefault
                            ? ":/res/colors.cfg"
                            : ":/res/colors_blue.cfg";
  loadColorFromFile(cfgFilePath);
  cfgFilePath = FileSys::instance()->appCfgDir();
  if (style == StyleMgr::StyleType::kDefault)
    cfgFilePath.append("/colors.cfg");
  else
    cfgFilePath.append("/colors_blue.cfg");
  loadColorFromFile(cfgFilePath);
}

void ResourceHolder::setDftSize() {
  m_sizes["ButtonWidth"] = 40;
  m_sizes["ButtonHeight"] = 24;
  m_sizes["RoundCorner"] = 5;
  m_sizes["CtrlSpacing"] = 4;
}

QColor ResourceHolder::color(const QString& crName) {
  auto iter = m_colors.find(crName);
  if (iter != m_colors.end()) return iter->second;

  Q_ASSERT(false);
  return QColor(Qt::GlobalColor::black);
}

int ResourceHolder::size(const QString& sizeName) {
  auto iter = m_sizes.find(sizeName);
  if (iter != m_sizes.end()) return iter->second;

  Q_ASSERT(false);
  return -1;
}

void ResourceHolder::changeStyle(StyleMgr::StyleType style) {
  m_colors.clear();
  loadColors(style);
}

void ResourceHolder::loadColorFromFile(const QString& cfgPath) {
  QJsonDocument doc = CoreUtility::openJsonDoc(cfgPath);
  if (doc.isNull()) return;

  QJsonObject colorObj = doc.object().take("colors").toObject();
  for (auto iter = colorObj.constBegin(); iter != colorObj.constEnd(); ++iter) {
    const QString& crKey = iter.key();
    int crValue = iter.value().toString().toInt(nullptr, 16);  // TODO异常处理?
    m_colors[crKey] = crValue;
  }
}

StyleMgr& StyleMgr::instance() {
  static StyleMgr sm;
  return sm;
}

StyleMgr::StyleType StyleMgr::getColorStyle() { return m_style; }

QColor StyleMgr::color(const QString& crName) { return m_res->color(crName); }

int StyleMgr::size(const QString& sizeName) { return m_res->size(sizeName); }

void StyleMgr::changeStyle(StyleType style) {
  if (m_style == style) return;
  m_res->changeStyle(style);

  // TODO 通知UI，参考QStyle?
}

QString LoadExternalQSS(const QDir& dir) {
  QString ret;
  QFileInfoList fileList = dir.entryInfoList({"*.qss"}, QDir::Files);
  for (int i = 0; i < fileList.size(); i++) {
    qDebug() << fileList.at(i).absoluteFilePath();
    QFile file(fileList.at(i).absoluteFilePath());
    if (file.open(QIODevice::ReadOnly)) {
      QString style = file.readAll();
      file.close();

      ret += style;
    }
  }

  return ret;
}

QString StyleMgr::appStyleSheet() {
  static QString s_styleSheet = QStringLiteral(
      "QLineEdit{background-color:#%1;color:#%2;border:1px solid "
      "#%3;border-radius:2px}"
      "QLineEdit:hover{background-color:#%4;}"
      "QLineEdit:focus{border:1px solid #%5;color:#%6}"
      "QLineEdit:read-only{border:1px solid #%3}"
      "QLineEdit{lineedit-password-character:42;}"
      "QLineEdit:disabled{color:#%11;}"
      "QComboBox QAbstractItemView {border: 1px solid #%7;border-radius:2px;}"
      "QComboBox QAbstractItemView::item {height:24px;}"
      "QPushButton "
      "{background-color:#%8;color:#%9;border:none;border-radius:2px;}"
      "QPushButton:disabled{background-color:#%10;color:#%11;}"
      "QPushButton#grey{background-color:#%12;}"
      "QPushButton:hover{background-color:#%13;}"
      "QPushButton:pressed{background-color:#%14;background-position: center; "
      "padding-top: 2px; padding-bottom: 2px; padding-left: 2px; "
      "padding-right: 2px;}"
      "QPushButton#grey:hover{background-color:#%13;}"
      "QPushButton#grey:pressed{background-color:#%14;background-position: "
      "center; padding-top: 2px; padding-bottom: 2px; padding-left: 2px; "
      "padding-right: 2px;}"
      "QLabel {color:#%2;}"
      "QLabel:disabled {color:#%11;background:transparent;}"
      "QMenu {border:1px solid "
      "#%3;background-color:#%1;color:#%2;border-radius:2px;margin:0px;}"
      "QMenu::item:selected{background-color:#%4;}"
      "QMenu::item:disabled{background-color:#%10;}"
      "QToolTip{background-color:#%1;color:#%2;border:1px solid "
      "#%4;border-radius:2px;}");

  QString ss =
      s_styleSheet.arg(StyleMgr::instance().color("BackNormal").rgb(), 0, 16)
          .arg(StyleMgr::instance().color("TextNormal").rgb(), 0, 16)
          .arg(StyleMgr::instance().color("BorderNormal").rgb(), 0, 16)
          .arg(StyleMgr::instance().color("Hover").rgb(), 0, 16)
          .arg(StyleMgr::instance().color("Highlight").rgb(), 0, 16)
          .arg(StyleMgr::instance().color("Highlight").rgb(), 0, 16)
          .arg(StyleMgr::instance().color("BorderNormal").rgb(), 0, 16)
          .arg(StyleMgr::instance().color("ButtonNormal").rgb(), 0, 16)
          .arg(StyleMgr::instance().color("TextNormal").rgb(), 0, 16)
          .arg(StyleMgr::instance().color("ButtonDisable").rgb(), 0, 16)
          .arg(StyleMgr::instance().color("TxtDisabled").rgb(), 0, 16)
          .arg(StyleMgr::instance().color("ButtonDisable").rgb(), 0, 16)
          .arg(StyleMgr::instance().color("Hover").rgb(), 0, 16)
          .arg(StyleMgr::instance().color("ButtonPressed").rgb(), 0, 16);

  QString strFile(":/widgets/scrollBar.qss");
  if (StyleMgr::StyleType::kBlue == m_style) {
    strFile = ":/widgets/scrollBar_blue.qss";
  }

  QFile file(strFile);
  bool ret = file.open(QFile::ReadOnly);
  QString str = file.readAll();
  ss += str;

  QDir qssDir(FileSys::instance()->runRootDir() + "/qss");
  ss += LoadExternalQSS(qssDir);

  return ss;
}

StyleMgr::StyleMgr() {
  QSettings settings(
      FileSys::instance()->writeableAppCfgDir() + "/globalsettings.ini",
      QSettings::IniFormat);
  settings.beginGroup("User");
  int nTheme = settings.value("Theme", 1).toInt();
  settings.endGroup();

  m_res = new ResourceHolder();
  m_style = (StyleType)nTheme;
  m_res->init(m_style);
}

QColor StyleMgr::BlendColor(QColor src, QColor dest, unsigned char alpha) {
  if (alpha == 255)
    return dest;
  else if (alpha == 0)
    return src;

  int r = src.red() + (((dest.red() - src.red()) * alpha) >> 8);
  int g = src.green() + (((dest.green() - src.green()) * alpha) >> 8);
  int b = src.blue() + (((dest.blue() - src.blue()) * alpha) >> 8);

  return QColor(r, g, b);
}
